package com.intramirror.product.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.intramirror.product.entity.Category;
import com.intramirror.product.entity.Product;
import com.intramirror.product.entity.Promotion;
import com.intramirror.product.enums.PromotionRuleTypeEnum;
import com.intramirror.product.mapper.CategoryMapper;
import com.intramirror.product.mapper.ProductMapper;
import com.intramirror.product.mapper.PromotionMapper;
import com.intramirror.product.mapper.PromotionRuleMapper;
import com.intramirror.product.service.IPromotionService;
import com.intramirror.product.utils.ConvertUtil;
import com.intramirror.product.vo.BrandEntity;
import com.intramirror.product.vo.CategoryEntity;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service(value = "promotionService")
public class PromotionServiceImpl implements IPromotionService {
    private static final Logger LOGGER = LoggerFactory.getLogger(PromotionServiceImpl.class);

    @Autowired
    PromotionRuleMapper promotionRuleMapper;

    @Autowired
    CategoryMapper categoryMapper;

    @Autowired
    PromotionMapper promotionMapper;

    @Autowired
    ProductMapper productMapper;

    private void removeExcludeProduct(Long promotionId) {
        Category param = new Category();
        param.setEnabled(true);
        List<Category> listDBCategory = categoryMapper.listAllCategoryByConditions(param);
        List<Map<String, Object>> listExcludeRule = promotionRuleMapper.listExcludeRulePromotion(promotionId);
        if (listExcludeRule != null) {
            for (Map<String, Object> excludeRule : listExcludeRule) {
                List<BrandEntity> listBrand = JSONObject.parseArray((String) excludeRule.get("brands"), BrandEntity.class);
                List<CategoryEntity> listCategory = JSONObject.parseArray((String) excludeRule.get("categorys"), CategoryEntity.class);
                Long vendorId = (Long) excludeRule.get("vendorId");

                for (CategoryEntity category : listCategory) {
                    for (Category dbCategory : listDBCategory) {
                        if (dbCategory.getCategoryId().longValue() == category.getCategoryId().longValue()) {
                            category.setLevel(dbCategory.getLevel());
                        }
                    }
                }

                for (BrandEntity brand : listBrand) {
                    Long brandId = brand.getBrandId() == -1 ? null : brand.getBrandId();
                    List<Long> listCategoryId = new ArrayList<>();
                    for (CategoryEntity category : listCategory) {
                        if (category.getLevel() == 3) {
                            listCategoryId.add(category.getCategoryId());
                        }
                    }
                    promotionRuleMapper.removeExcludeSnapshotProduct(promotionId, vendorId, (String) excludeRule.get("seasonCode"), brandId, listCategoryId);
                }
            }
        }

        promotionRuleMapper.removeExcludeProductGroupFromSnapshot(promotionId);
        promotionRuleMapper.removeExcludeProductFromSnapshotProduct(promotionId);

    }

    @Transactional
    @Override
    public void refreshSnapshotProductByPromotion(Long promotionId) {

        promotionRuleMapper.removeSnapshotProduct(promotionId);
        List<Map<String, Object>> listIncludeRule = promotionRuleMapper.listIncludeRulePromotion(promotionId);

        Category param = new Category();
        param.setEnabled(true);
        List<Category> listDBCategory = categoryMapper.listAllCategoryByConditions(param);

        for (Map<String, Object> includeRule : listIncludeRule) {

            List<BrandEntity> listBrand = JSONObject.parseArray((String) includeRule.get("brands"), BrandEntity.class);
            List<CategoryEntity> listCategory = JSONObject.parseArray((String) includeRule.get("categorys"), CategoryEntity.class);
            Long vendorId = (Long) includeRule.get("vendorId");
            for (CategoryEntity category : listCategory) {
                for (Category dbCategory : listDBCategory) {
                    if (dbCategory.getCategoryId().longValue() == category.getCategoryId().longValue()) {
                        category.setLevel(dbCategory.getLevel());
                    }
                }
            }

            for (BrandEntity brand : listBrand) {
                Long brandId = brand.getBrandId() == -1 ? null : brand.getBrandId();

                List<Long> listCategoryId = new ArrayList<>();
                for (CategoryEntity category : listCategory) {
                    if (category.getLevel() == 3) {
                        listCategoryId.add(category.getCategoryId());
                    }
                }
                LOGGER.info("Category id size {}", listCategoryId.size());
                promotionRuleMapper.generateRuleToSnapshotProduct(promotionId, (Long) includeRule.get("ruleId"), vendorId,
                        (String) includeRule.get("seasonCode"), brandId, listCategoryId);
            }
        }

        removeExcludeProduct(promotionId);
        //更新刷新时间
        promotionRuleMapper.updatePromotionRefreshAt(promotionId);
    }

    private boolean vendorMatch(Long productVendor, Long ruleVendor) {
        return productVendor.longValue() == ruleVendor || ruleVendor == -1;
    }

    private boolean seasonCodeMatch(String productSeasonCode, String ruleSeasonCode) {
        return productSeasonCode.equalsIgnoreCase(ruleSeasonCode);
    }

    private boolean categoryMatch(Long productCategoryId, List<CategoryEntity> listCategory) {
        for (CategoryEntity category : listCategory) {
            if (category.getCategoryId().longValue() == productCategoryId) {
                return true;
            }
        }
        return false;
    }

    private boolean brandMatch(Long brandId, List<BrandEntity> listBrand) {
        for (BrandEntity brand : listBrand) {
            if (brand.getBrandId() == -1 || brand.getBrandId().longValue() == brandId) {
                return true;
            }
        }
        return false;
    }

    private void addProductForIncludeRule(Long promotionId, Long productId) {
        LOGGER.debug("Start to add product {} to snapshot for promotion {}.", productId, promotionId);

        List<Map<String, Object>> listIncludeRule = promotionRuleMapper.listIncludeRulePromotion(promotionId);
        Product product = productMapper.selectByPrimaryKey(productId);

        Long ruleId = null;
        boolean needAdd = false;

        /* 正向规则 */
        for (Map<String, Object> includeRule : listIncludeRule) {
            Long vendorId = ConvertUtil.toLong(includeRule.get("vendorId"));
            List<BrandEntity> listBrand = JSONObject.parseArray((String) includeRule.get("brands"), BrandEntity.class);
            List<CategoryEntity> listCategory = JSONObject.parseArray((String) includeRule.get("categorys"), CategoryEntity.class);
            String seasonCode = ConvertUtil.toString(includeRule.get("seasonCode"));

            if (vendorMatch(product.getVendorId(), vendorId) && seasonCodeMatch(product.getSeasonCode(), seasonCode) && categoryMatch(product.getCategoryId(),
                    listCategory) && brandMatch(product.getBrandId(), listBrand)) {
                needAdd = true;
                LOGGER.info("Find rule in promotion {} for include product {}", promotionId, productId);
                ruleId = ConvertUtil.toLong(includeRule.get("ruleId"));
                break;
            }
        }

        if (!needAdd) {
            return;
        }

         /* 逆向规则 */
        List<Map<String, Object>> listExcludeRule = promotionRuleMapper.listExcludeRulePromotion(promotionId);
        if (listExcludeRule != null) {
            for (Map<String, Object> excludeRule : listExcludeRule) {
                List<BrandEntity> listBrand = JSONObject.parseArray((String) excludeRule.get("brands"), BrandEntity.class);
                List<CategoryEntity> listCategory = JSONObject.parseArray((String) excludeRule.get("categorys"), CategoryEntity.class);
                Long vendorId = ConvertUtil.toLong(excludeRule.get("vendorId"));
                String seasonCode = ConvertUtil.toString(excludeRule.get("seasonCode"));

                if (vendorMatch(product.getVendorId(), vendorId) && seasonCodeMatch(product.getSeasonCode(), seasonCode) && categoryMatch(
                        product.getCategoryId(), listCategory) && brandMatch(product.getBrandId(), listBrand)) {
                    LOGGER.info("Find exclude rule in promotion {} for include product {}", promotionId, productId);
                    needAdd = false;
                    break;
                }
            }
        }

        if (!needAdd) {
            return;
        }

        /* 逆向Product */
        List<Map<String, Object>> result = promotionRuleMapper.selectProductFromExcludeProductRule(promotionId, productId);
        if (result != null && result.size() > 0) {
            return;
        }

        result = promotionRuleMapper.selectProductFromExcludeGroupRule(promotionId, productId);
        if (result == null || result.size() <= 0) {
            LOGGER.info("===>Start to add product for promotion={},rule={},products={}.", promotionId, ruleId, productId);
            promotionRuleMapper.addProductForIncludeRule(promotionId, ruleId, productId);
        }

    }

    private void addProductsForIncludeRule(Long promotionId, List<Long> productIds) {
        for (Long productId : productIds) {
            addProductForIncludeRule(promotionId, productId);
        }
    }

    @Transactional
    @Override
    public void refreshSnapshotForAddProduct(Long productId) {
        List<Promotion> listPromotion = promotionMapper.getAllPromotion();
        for (Promotion promotion : listPromotion) {
            addProductForIncludeRule(promotion.getPromotionId(), productId);
        }
    }

    @Transactional
    @Override
    public void refreshBatchSnapshotForAddProduct(List<Long> productIds) {
        List<Promotion> listPromotion = promotionMapper.getAllPromotion();

        for (Promotion promotion : listPromotion) {
            addProductsForIncludeRule(promotion.getPromotionId(), productIds);
        }
    }

    @Override
    public List<Map<String, Object>> getActivePromotionByBannerId(Long bannerId) throws Exception {

        List<Map<String, Object>> promotions = Lists.newArrayList();
        Map<String, Object> activePromotion = promotionMapper.getActivePromotionByBannerIdResultMap(bannerId);
        if (activePromotion != null) {
            Map<String, Object> activeMap = Maps.newHashMap();

            activeMap.put("promotionId", activePromotion.get("promotionId"));
            activeMap.put("bannerId", activePromotion.get("bannerId"));
            activeMap.put("promotionName", activePromotion.get("promotionName"));
            activeMap.put("startTime", activePromotion.get("startTime").toString());
            activeMap.put("status", "Active");
            activeMap.put("bannerImg", activePromotion.get("bannerImg") == null ? "" : activePromotion.get("bannerImg").toString());

            promotions.add(activeMap);
        }
        List<Map<String, Object>> otherPromotions = promotionMapper.getOtherPromotionsByBannerId(bannerId);
        if (otherPromotions.size() > 0) {
            Long promotionId = activePromotion.get("promotionId") == null ? 0L : Long.valueOf(activePromotion.get("promotionId").toString());
            for (Map<String, Object> otherMap : otherPromotions) {
                if (otherMap.get("promotionId").equals(promotionId)) {
                    continue;
                } else {
                    Map<String, Object> promotionMap = Maps.newHashMap();

                    promotionMap.put("promotionId", otherMap.get("promotionId"));
                    promotionMap.put("bannerId", otherMap.get("bannerId"));
                    promotionMap.put("promotionName", otherMap.get("promotionName"));
                    promotionMap.put("startTime", otherMap.get("startTime").toString());
                    promotionMap.put("status", otherMap.get("status"));
                    promotionMap.put("bannerImg", otherMap.get("bannerImg") == null ? "" : otherMap.get("bannerImg").toString());

                    promotions.add(promotionMap);
                }
            }

        }

        return promotions;
    }

    @Override
    public int setCampaignActiveTime(Promotion campaign) {
        //同一个banner下不能有相同开始时间
        Promotion startTimePromotion = promotionMapper.getPromotionByStartTime(campaign);
        if (startTimePromotion != null) {
            //存在
            return 0;
        } else {
            return promotionMapper.updateByPrimaryKeySelective(campaign);
        }
    }

    @Transactional
    @Override
    public Promotion copyCampaignToBanner(Long bannerId, Long campaignId, String campaignName, Long startTime) {
        Promotion checkPromotion = new Promotion();
        checkPromotion.setBannerId(bannerId);
        checkPromotion.setStartTime(new Date(startTime));
        boolean check = checkStartTime(checkPromotion);
        if (check) {
            Promotion newPromotion = generateCampaign(bannerId, campaignId, campaignName, startTime);
            LOGGER.info("The new promotion is {}.", newPromotion.getPromotionId());
            copyRuleForNewCampaign(campaignId, newPromotion.getPromotionId());
            copySeq(campaignId, newPromotion.getPromotionId());
            copyBrandHot(campaignId, newPromotion.getPromotionId());
            return newPromotion;
        } else {
            return null;
        }

    }

    private Promotion generateCampaign(Long bannerId, Long campaignId, String campaignName, Long startTime) {

        Map<String, Object> result = promotionMapper.selectPromotionBanner(bannerId);
        if (result == null) {
            return null;
        }

        Promotion oldPromotion = promotionMapper.selectByPrimaryKey(campaignId);
        Promotion newPromotion = new Promotion();
        newPromotion.setStartTime(new Date(startTime));
        newPromotion.setBannerId(bannerId);
        newPromotion.setBannerImg(oldPromotion.getBannerImg());
        newPromotion.setDescription(oldPromotion.getDescription());

        if ("1".equals(result.get("banner_pos_id").toString())) {
            newPromotion.setPosterImg(oldPromotion.getPosterImg());
        } else {
            newPromotion.setPosterImg("");
        }

        newPromotion.setPromotionName(campaignName);
        newPromotion.setEnabled(oldPromotion.getEnabled());
        int ret = promotionMapper.insertSelective(newPromotion);
        LOGGER.info("Generate promotion ret is {} -> {}.", ret, newPromotion.getPromotionId());
        return newPromotion;
    }

    private void copyRuleForNewCampaign(Long oldCampaignId, Long newCampaignId) {
        int includeNum = promotionMapper.copyIncludeRule(oldCampaignId, newCampaignId);
        int excludeNum = promotionMapper.copyExcludeRule(oldCampaignId, newCampaignId);
        int excludeProductNum = promotionMapper.copyExcludeProduct(oldCampaignId, newCampaignId);

        LOGGER.info("Copy rule from campaign {} to {}, include rule {}, exclude rule {}, exclude product {}.", oldCampaignId, newCampaignId, includeNum,
                excludeNum, excludeProductNum);
    }

    private void copySeq(Long oldCampaignId, Long newCampaignId) {
        int promotionSeq = promotionMapper.copyPromotionSeq(oldCampaignId, newCampaignId);
        int categorySeq = promotionMapper.copyCategorySeq(oldCampaignId, newCampaignId);
        int brandSeq = promotionMapper.copyBrandSeq(oldCampaignId, newCampaignId);
        int vendorSeq = promotionMapper.copyVendorSeq(oldCampaignId, newCampaignId);

        LOGGER.info("Copy seq from campaign {} to {}, promotion seq {}, category seq {}, brand seq {}, vendor seq {}.", oldCampaignId, newCampaignId,
                promotionSeq, categorySeq, brandSeq, vendorSeq);
    }

    private void copyBrandHot(Long oldCampaignId, Long newCampaignId) {
        int brandHot = promotionMapper.copyBrandHot(oldCampaignId, newCampaignId);
        LOGGER.info("Copy brand hot from campaign {} to {}, brand hot {}.", oldCampaignId, newCampaignId, brandHot);
    }

    @Override
    public String deleteCampaign(Promotion campaign) {
        Promotion promotion = promotionMapper.getActivePromotionByBannerId(campaign.getBannerId());
        if (promotion != null && campaign.getPromotionId().equals(promotion.getPromotionId())) {
            return promotion.getPromotionName() + "正在使用,不能进行删除操作！";
        } else {
            promotionMapper.deletePromotionByPrimaryKey(campaign.getPromotionId());
            return "ok";
        }
    }

    @Transactional
    @Override
    public int newCampaignByBanner(Long bannerId, String campaignName, Long startTime) {
        //添加到t_promotion
        Promotion promotion = new Promotion();
        promotion.setBannerId(bannerId);
        promotion.setPromotionName(campaignName);
        promotion.setStartTime(new Date(startTime));
        promotion.setCreatedAt(new Date());
        promotion.setBannerImg("");
        promotion.setPosterImg("");
        promotion.setUpdatedAt(new Date());
        promotion.setEnabled(true);
        boolean check = checkStartTime(promotion);
        Long result = 0L;
        if (check) {
            result = promotionMapper.insert(promotion);
        }
        if (result > 0) {
            Long id = promotion.getPromotionId();
            promotionMapper.insertPromotionRule(id);
            return 1;
        } else {
            return 0;
        }
    }

    @Override
    public List<Map<String, Object>> getPromotionBoutiqueHasRuleList(Long promotionId) {
        return promotionRuleMapper.getPromotionBoutiqueHasRuleList(promotionId);
    }

    @Override
    public List<Map<String, Object>> getPromotionBoutiqueSeason(Map<String, Object> params) {
        return promotionRuleMapper.getPromotionBoutiqueSeason(params);
    }

    @Override
    public List<Map<String, Object>> getPromotionBoutiqueProductCountBySeason(Map<String, Object> params) {
        return promotionRuleMapper.getPromotionBoutiqueProductCountBySeason(params);
    }

    @Override
    public Integer getPromotionBoutiqueExcludeProductCount(Long promotionId) {
        return promotionRuleMapper.getPromotionBoutiqueExcludeProductCount(promotionId);
    }

    @Override
    public Map<String, Object> getPromotionById(Long promotionId) {
        Map<String, Object> resultMap = promotionRuleMapper.getPromotionById(promotionId);
        if (resultMap != null) {
            resultMap.put("startTime", resultMap.get("startTime").toString());
            if (resultMap.get("refreshTime") != null) {
                resultMap.put("refreshTime", resultMap.get("refreshTime").toString());
            }
            if (resultMap.get("saveAt") != null) {
                resultMap.put("saveAt", resultMap.get("saveAt").toString());
            }
        }
        return resultMap;
    }

    @Transactional
    @Override
    public Boolean removePromotionRule(String seasonCode, Long vendor, PromotionRuleTypeEnum ruleType, Long promotionId) {
        Boolean flag = false;
        String tableName = "";
        if (ruleType == PromotionRuleTypeEnum.INCLUDE_RULE) {
            tableName = "t_promotion_include_rule";
        } else if (ruleType == PromotionRuleTypeEnum.EXCLUDE_RULE) {
            tableName = "t_promotion_exclude_rule";
        }

        if (seasonCode.equals("null") || seasonCode.equals("")) {
            seasonCode = null;
        }

        flag = promotionRuleMapper.removeIncludeRule(tableName, seasonCode, vendor, promotionId) > 0;
        return flag;
    }

    @Transactional
    @Override
    public Boolean removePromotionRuleByVendor(String seasonCode, Long vendor, Long promotionId) {
        promotionRuleMapper.updatePromotionSaveTime(promotionId);
        Boolean flag = false;
        //        if (seasonCode.equals("null") || seasonCode.equals("")) {
        //            seasonCode = null;
        //        }
        flag = promotionRuleMapper.removePromotionRuleByVendor(seasonCode, vendor, promotionId) > 0;
        return flag;
    }

    @Override
    public List<Map<String, Object>> getExcludeProductGroup(Long vendorId, String orderBy) {
        List<Map<String, Object>> resultMaps = promotionRuleMapper.getTags(vendorId, orderBy);
        if (resultMaps.size() > 0) {
            for (Map<String, Object> result : resultMaps) {
                result.put("createAt", result.get("createAt").toString());
            }
        }
        return resultMaps;
    }

    @Override
    public Boolean addExcludeProductGroup(Long promotionId, Long tagId) {
        boolean flag = false;
        Long id = promotionRuleMapper.findPromotionExcludeGroupByTagId(tagId, promotionId);
        if (id != null) {
            flag = false;
        } else {
            promotionRuleMapper.updatePromotionSaveTime(promotionId);
            promotionRuleMapper.addExcludeProductGroup(promotionId, tagId);
            flag = true;
        }
        return flag;
    }

    @Override
    public List<Map<String, Object>> excludeProductGroupByVendor() {
        List<Map<String, Object>> mapLists = promotionRuleMapper.getVendorInfoByTag();
        return mapLists;
    }

    @Override
    public int deleteExcludeProductGroup(List<Long> ids) {
        promotionRuleMapper.updatePromotionSaveTimeByExcludeProductGroupIds(ids);
        return promotionRuleMapper.deleteExcludeProductGroup(ids);
    }

    @Override
    public List<Map<String, Object>> getExcludeProductGroupByPromotionId(Long promotionId) {
        return promotionRuleMapper.getExcludeProductGroupByPromotionId(promotionId);
    }

    public boolean checkStartTime(Promotion promotion) {
        //日期验证
        Promotion startTimePromotion = promotionMapper.getPromotionByBannerId(promotion);
        if (startTimePromotion != null) {
            //存在
            return false;
        } else {
            return true;
        }
    }
}
